package cn.amossun.starter.event.handler;

import cn.hutool.core.collection.CollectionUtil;
import cn.amossun.starter.event.listener.SimpleRemoteEventMessageListener;
import cn.amossun.starter.event.property.EventContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.listener.MessageListenerContainer;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import java.util.HashMap;
import java.util.Map;

@Slf4j
public class ListenerContainerInitializer implements InitializingBean, DisposableBean {

    private final EventContext eventContext;

    private final Integer prefetchCount;

    private final SimpleRemoteEventMessageListener simpleRemoteEventMessageListener;

    private final CachingConnectionFactory cachingConnectionFactory;

    private final SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory;

    public ListenerContainerInitializer(EventContext eventContext,
                                        Integer prefetchCount,
                                        SimpleRemoteEventMessageListener simpleRemoteEventMessageListener,
                                        CachingConnectionFactory cachingConnectionFactory,
                                        SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory) {
        this.eventContext = eventContext;
        this.prefetchCount = prefetchCount;
        this.simpleRemoteEventMessageListener = simpleRemoteEventMessageListener;
        this.cachingConnectionFactory = cachingConnectionFactory;
        this.simpleRabbitListenerContainerFactory = simpleRabbitListenerContainerFactory;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        initialize();
    }

    void initialize() {
        eventContext.getListenerContexts().stream().forEach(listenerContext -> {
            Map<String, Object> args = new HashMap<String, Object>(1 + listenerContext.getArgumentsMap().size()) {{
                put("x-priority", listenerContext.getPriority());
                if(CollectionUtil.isNotEmpty(listenerContext.getArgumentsMap())) {
                    putAll(listenerContext.getArgumentsMap());
                }
            }};

            SimpleMessageListenerContainer listenerContainer = simpleRabbitListenerContainerFactory.createListenerContainer();
            listenerContainer.setMessageListener(simpleRemoteEventMessageListener);
            listenerContainer.setConnectionFactory(cachingConnectionFactory);
            listenerContainer.setPrefetchCount(listenerContext.getPrefetchCount() < 1 ? prefetchCount : listenerContext.getPrefetchCount());
            listenerContainer.setExclusive(listenerContext.isExclusive());
            listenerContainer.setAmqpAdmin(listenerContext.getAmqpAdmin());
            listenerContainer.setConcurrency(listenerContext.getConcurrency());
            listenerContainer.setAcknowledgeMode(listenerContext.getAckMode());
            listenerContainer.addQueueNames(listenerContext.getQueueNames().toArray(new String[]{}));
            listenerContainer.setAutoStartup(listenerContext.getAutoStartup());
            listenerContainer.setConsumerArguments(args);

            if(listenerContext.getAutoStartup()) {
                listenerContainer.start();
            }
            eventContext.putListenerContainer(listenerContainer);
        });
    }

    @Override
    public void destroy() throws Exception {
        for (MessageListenerContainer listenerContainer : eventContext.getListenerContainers()) {
            if (listenerContainer instanceof DisposableBean) {
                try {
                    ((DisposableBean) listenerContainer).destroy();
                }
                catch (Exception ex) {
                    log.warn("Failed to destroy listener container [" + listenerContainer + "]", ex);
                }
            }
        }
    }

}
